from django import http
from django.shortcuts import render

# Create your views here.
from django.views import View

from apps.verifications.constants import IMAGE_CODE_EXPIRE_TIME, SMS_CODE_EXPIRE_TIME
from libs.captcha.captcha import captcha
from django_redis import get_redis_connection

from libs.yuntongxun.sms import CCP
from utils.response_code import RETCODE
import logging

logger = logging.getLogger('django')

"""
一、写下需求（前端要做什么，后端要做什么）
二、大体思路（后端的大体思路）
三、把详细思路完善下（纯后端
四、确定我们的请求方式和路由
"""
"""
一、写下需求（前端要做什么，后端要做什么）
    前端生成一个随机码（UUID），把这个随机码给后端
    后端需要生成随机验证码，并把随机验证码存到Redis中，Redis中的数据是 uuid:xxx
    
二、大体思路（后端的大体思路）
    1、生成图片验证码和获取图片验证码的内容
    2、链接Redis，将图片验证码保存起来，uuid:xxx 有有效期
    3、返回图片验证码
    
三、把详细思路完善下（纯后端）
    1、生成图片验证码和获取图片验证码的内容
    2.1、链接Redis，
    2.2、将图片验证码保存起来，uuid:xxx 有有效期
    3、返回图片验证码
四、确定我们的请求方式和路由
    GET方式（因为是img标签）
    /image_codes/(?P<uuid>[\w-]+)/
"""


class ImageCodeView(View):
    def get(self, requset, uuid):
        # 1、生成图片验证码和获取图片验证码的内容
        text, image = captcha.generate_captcha()
        # 2.1、链接Redis，
        redis_conn = get_redis_connection('code')
        # 2.2、将图片验证码保存起来，uuid: xxx  有有效期
        # redis_conn.setex(key, senconds, value)
        # uuid那里加了一个img_前缀
        # redis_conn.setex('img_%s' % uuid, 120, text)  # 这个120是存在时间，120s后过期
        redis_conn.setex('img_%s' % uuid, IMAGE_CODE_EXPIRE_TIME, text)
        # 3、返回图片验证码
        # content_type 是MIME类型，大类/小类
        # 如果不加的话，默认是文本，而不是图片
        return http.HttpResponse(image, content_type='image/jpeg')


"""
用户点击短信验证码按钮，给用户发短信

一、写下需求（前端要做什么，后端要做什么）
    前端：收集手机号、用户输入的验证码内容和uuid
    通过ajax发送给后端
二、大体思路（后端的大体思路）
    接受参数
    验证参数
    发送短信
三、把详细思路完善下（纯后端）
    1、接收参数：手机号，验证码，uuid
    2、验证参数
        2.1、验证手机号是否合法
        2.2、这三个参数必须有
    3、验证用户输入的验证码和服务器保存的是否一致
        3.1、获取用户输入的验证码
        3.2、获取服务器的验证码
        3.3、比对
    4、先生成一个随机短信验证码
    5、短信验证码保存起来（保存在Redis中）
    6、再发送短信
        
四、确定我们的请求方式和路由
    GET 
        1、提取URL特定部分，如weather/beijing/2021
        2、查询字符串，如weather/?address=beijing&year=2021
        3、混合， /sms_codes/(?P<mobile>1[3-9]\d{9})/？uuid=1234&imagecode=xxx
"""


class SmsCodeView(View):
    def get(self, request, mobile):
        # 1、接收参数：手机号，验证码，uuid
        image_code = request.GET.get('image_code')
        uuid = request.GET.get('image_code_id')
        # 2、验证参数
        #     2.1、验证手机号是否合法
        #     2.2、这三个参数必须有
        if not all([mobile, image_code, uuid]):
            # ajax请求要返回json
            # code是响应码
            return http.JsonResponse({'code': RETCODE.NECESSARYPARAMERR, 'errormsg': '参数不齐'})
        # 3、验证用户输入的验证码和服务器保存的是否一致
        #     3.1、获取用户输入的验证码
        #     3.2、获取服务器的验证码
        try:
            redis_con = get_redis_connection('code')
            redis_code = redis_con.get('img_%s' % uuid)
            if redis_code is None:
                return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errormsg': '验证码过期'})
            # 添加一个删除验证码的逻辑，防止用户再次对比
            # Redis也是保存在内存中的，用完删掉节省空间
            redis_con.delete('img_%s' % uuid)
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errormsg': 'redis有异常'})
        #     3.3、比对
        #       获取Redis的数据都是bytes类型
        if redis_code.decode().lower() != image_code.lower():
            return http.JsonResponse({'code': RETCODE.SMSCODERR, 'errormsg': '短信验证码错误'})

        # 判断标记位是否为1
        send_flag = redis_con.get('send_flag_%s' % mobile)
        if send_flag:
            return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errormsg': '操作太频繁'})
        # 4、先生成一个随机短信验证码
        from random import randint
        # sms_code = '%06d'%randint(0, 999999)  # 不满6位，用0补齐
        sms_code = randint(100000, 999999)
        # 5、短信验证码保存起来（保存在Redis中）
        # mobile:value

        # 管道让两个链接Redis的命令合成了一次链接，优化了性能
        # ① 创建管道
        pipe = redis_con.pipeline()
        # redis_con.setex('sms_%s' % mobile, SMS_CODE_EXPIRE_TIME, sms_code)
        # redis_con.setex('send_flag_%s' % mobile, 60, 1)
        # ②
        pipe.setex('sms_%s' % mobile, SMS_CODE_EXPIRE_TIME, sms_code)
        pipe.setex('send_flag_%s' % mobile, 60, 1)
        # ③让管道执行
        pipe.execute()

        # 6、再发送短信
        # 参数1：给谁发
        # 参数2：【云通讯】您使用的是云通讯短信模板，您的验证码是{1}，请于{2}分钟内正确输入
        # 参数3：使用的模板，测试默认用1
        # CCP().send_template_sms(mobile, [sms_code, SMS_CODE_EXPIRE_TIME / 60], 1)
        # 我们的函数需要通过delay调用，才能添加到broker中
        from celery_tasks.sms.tasks import send_sms_code
        # send_sms_code的参数平移到delay中
        send_sms_code.delay(mobile, sms_code)

        return http.JsonResponse({'code': RETCODE.OK, 'errormsg': 'ok'})
